#ifndef GAME_HH
#define GAME_HH

#include <QPainter>
#include <QFontDatabase>
#include <QGraphicsView>
#include <QGraphicsScene>
#include <QGraphicsPixmapItem>
#include <QGraphicsProxyWidget>
#include <QWidget>
#include <QEvent>
#include <QMouseEvent>
#include <QPushButton>
#include <QVBoxLayout>
#include <QGridLayout>
#include <QDialog>
#include <QLineEdit> // Pascal included this one
#include <QIcon> // Laurent included this one
#include <string>
#include <map>
#include "player.hh"
#include "room.hh"
#include "resourceloader.hh"

/*
   Instanciee via le main cette classe represente la
   fenetre (herite de QWidget)
   Les boutons du menu y sont stockes et l'affichage se
   fait a partir de cette classe
*/
class Game : QWidget{
  Q_OBJECT
private: 
  Player player_;

  /*
    C'est le numero de la partie pour permettre d'avoir 
    plusieurs sauvegardes. 
    Il est pris en compte lors de la sauvegarde 
  */
  std::string idGame_;

  /*
    id de la salle actuellement visitee dans listRoom_
    Est mis a jour apres chaque TextEvent.changeRoom()
  */
  int idCurrentRoom_;

  /*
    A chaque fois que le joueur appuie sur la fleche du
    haut ou du bas pour faire defiler son inventaire
    on incremente ou decremente cette valeur. Permet de
    recuperer l'index (dans player_.listItem_) de l'objet
    correspondant au bouton sur lequel on a clique
  */
  int countSelectorItem_;

  /*
    Lors d'un clic sur objet de l'inventaire permet de savoir
    quel item est actuellement selectionne
  */
  int selectedIndexItem_;

  /*
    La liste des pieces actuellement traversables
  */
  std::vector<Room> vectorRoom_;

  /*
    Ce layout principal contient la zone d'affichage 
    ou seront mis la scene et les elements cliquables ainsi
    que la zone ou sont les commandes
  */
  QVBoxLayout *mainLayout_;

  /*
    La zone ou les messages/dialogues vont apparaitre
  */
  QLabel* dialogZone_;
  QPushButton* nextDialogButton_;
  QHBoxLayout* dialogZoneLayout_;
  QWidget* dialogSceneContainer_;
  QGraphicsProxyWidget* proxyDialogZone_;
  QGraphicsPixmapItem* dialogCurrentFace_;

  /*
    Le systeme de signaux et slots ne pemet pas de
    passer une valeur au signal clicked() et l'utilisation
    d'un QSignalMapper est comme cette methode de variable
  */
  int gNextTextEventId_;

  /*
    Comme pour l'attribut precedent mais avec la prochaine salle
    a visiter
  */

  int gNextRoomId_;

  /*
    Pendant un message/dialogue il ne faut pas intercepter
    les clics sur la scene SAUF sur le bouton de message suivant
  */
  bool isDialogMode_;

  /*
    La ou sont mis les elements graphiques montrant le
    deroulement du jeu
  */
  QGraphicsScene scene_;
  QGraphicsView* view_;

  /*
    L'image de fond utilisee pour les decors
  */
  QGraphicsPixmapItem background_;

  /*
    Contient les pixmap et les Elements respectifs qu'ils representent
  */
  std::map<QGraphicsPixmapItem*, Element*> poolGraphicalElements_;

  /*
    Les boutons d'action, l'inventaire et les boutons 
    quitter et haut et bas y sont presents
  */
  QGridLayout *actionBar_;

  /*
    Suite a l'assimilation de la classe messageEngine
    les illustrations des personages sont stockees ici
  */
  std::map<std::string, QGraphicsPixmapItem*> faces_;

  /*
    La liste des Widgets du layout actuel
    Afin de pouvoir les supprimer au besoin
  */
  QList<QWidget*> listwidgets_;

  /*
    Les boutons de la barre d'actions (peut-etre les ranger dans une liste ?)
  */

  std::map<std::string, QPushButton*> actionButtons_;

  /*
    Table de hash contenant a chaque cle un bouton
    Sert a remplacer une longue liste de declaration
  */
  std::map<int, QPushButton*> itemButtons_;

  QPushButton* b_PreviousItem_;
  QPushButton* b_NextItem;
  QPushButton* b_Quit_;

public:
  Game(); // cree le menu
  ~Game();

  void SetUp(); // ancien contenu du constructeur : met en place la scene et la barre d'actions
  void loadItems();

  Player getPlayer();
  std::string getIdGame();
  int getCountSelectorItem();
  int getIdCurrentRoom();
  std::vector<Room> getVectorRoom();
  void addRoom(Room&);

  Room* getCurrentRoom(int);

  void cleanRoom();

  /*
    Intercepte les clics sur la scene pour le processus
    de mise a jour des actions disponibles et fournit
    les infos au TouchManager
  */
  bool eventFilter(QObject*, QEvent*);

  /*
    Cette methode appellee apres affichage du message gere ajout/suppression des objets
  */
  void manageTextEvent(TextEvent*);

  /*
    La gestion des visages durant les dialogues
  */
  void manageFaceTextEvent(TextEvent*);

  void manageMessage(int, Room*);

  /*
    Affiche le texte issu de l'evenement passe en parametre
    qui est recupere dans listRoom_[currentRoom_].listTextEvents[id]
  */
  void displayMessage(std::string);

  /*
    Quand un TextEvent contient un changement de salle,
    displayMessage et appelle cette methode
   */
  void changeRoom(int);

  /*
    Affiche l'image de fond de la scene
    ResourceLoader recupere le path dans le noeud src 
    de la salle correspondante dans le XML
    Puis affichage des elements interactifs
  */
  void render();
  
  /*
    La methode servant certainement de boucle de jeu
    En effet, juste apres l'instanciation d'un objet
    game dans le main, il y aura une methode qui se
    chargera de lire le XML de salles au fur et Ãƒ  
    mesure puisque comme toutes les salles du jeu 
    ne sont pas chargees en meme temps, il faut qu'une
    methode se charge de ces transitions
    Meme si le code de cette methode est encore inconnu
    je suis fortement convaincu qu'elle doit exister en 
    dehors d'un contexte de "boucle de jeu"
  */
  void run();

  /*
    Lors du clic sur element, il faut determiner si les
    actions sont faisables ou non. Pour cela il faut voir
    si il y a une dependance pour l'evenement lie a l'action
  */
  bool isEligibleAction(Room*, int);

  /*
    Quand le joueur clique sur un nouvel element il faut
    desactiver tous les boutons
  */
  void disableActionButtons();

  void disableInterfaceButtons();

  void assignCurrentRoom(Room**);

signals:
  void clickScene(int, int);

public slots:
  void executeNextDialog();
  void resolveSceneClick(int, int);
  // boutons du menu principal
  void clickcontinuer();
  void clicknouvelle();
  void clickquitter();
  // boutons de gestion de l'inventaire
  void clickItemButton(int);
  void clickUpDown(int);
  // boutons d'actions
  void clickGive();
  void clickOpen();
  void clickClose();
  void clickTake();
  void clickLook();
  void clickTalk();
  void clickUse();
  void clickPush();
  void clickPull();
  void loadgamenb(QString); // Pour continuer une partie. La string contient l'id de la partie et le numero de la salle a charger
};

#endif
